package com.love.marriage.userProfileInfo.service.impl;

import cn.afterturn.easypoi.excel.ExcelExportUtil;
import cn.afterturn.easypoi.excel.entity.ExportParams;
import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.love.marriage.cloud.vo.RedPacketVo;
import com.love.marriage.common.constants.RedisConstants;
import com.love.marriage.common.enums.ResultEnum;
import com.love.marriage.common.event.UserInviteRedPacketEvent;
import com.love.marriage.common.exceptions.LoginException;
import com.love.marriage.common.exceptions.SystemException;
import com.love.marriage.common.redisKey.LoginKey;
import com.love.marriage.common.vo.Audience;
import com.love.marriage.defaultAmountConfig.mapper.DefaultAmountConfigMapper;
import com.love.marriage.defaultAmountConfig.vo.DefaultAmountConfigVo;
import com.love.marriage.oss.service.FileInfoService;
import com.love.marriage.oss.vo.FileInfoVo;
import com.love.marriage.userActivityInfo.service.UserActivityInfoService;
import com.love.marriage.userActivityInfo.vo.UserActivityInfoVo;
import com.love.marriage.userInfo.mapper.UserInfoMapper;
import com.love.marriage.userInfo.service.UserInfoService;
import com.love.marriage.userInfo.vo.MemberAboutVo;
import com.love.marriage.userInfo.vo.UserInfoVo;
import com.love.marriage.userPartnerPreferences.mapper.UserPartnerPreferencesMapper;
import com.love.marriage.userPartnerPreferences.vo.UserPartnerPreferencesVo;
import com.love.marriage.userProfileInfo.entity.UserProfileInfo;
import com.love.marriage.userProfileInfo.mapper.UserProfileInfoMapper;
import com.love.marriage.userProfileInfo.service.UserProfileInfoService;
import com.love.marriage.userProfileInfo.vo.UserProfileInfoExportVo;
import com.love.marriage.userProfileInfo.vo.UserProfileInfoVo;
import com.love.marriage.userProfileInfo.vo.UserProfileVo;
import com.love.marriage.utils.IpUtils;
import com.love.marriage.utils.JwtTokenUtils;
import com.love.marriage.utils.RedisUtils;
import com.love.marriage.utils.StringUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.Workbook;
import org.springframework.beans.BeanUtils;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.time.LocalDate;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 * description:  用户档案表服务实现类
 * author:       mybatisPlus
 * createDate:   2024-10-12 21:01:09
 * version:      1.0.0
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class UserProfileInfoServiceImp extends ServiceImpl<UserProfileInfoMapper, UserProfileInfo> implements UserProfileInfoService {

    private final UserProfileInfoMapper userProfileInfoMapper;

    private final UserInfoService userInfoService;

    private final RedisUtils redisUtils;

    private final UserActivityInfoService userActivityInfoService;

    private final Audience audience;

    private final JwtTokenUtils jwtTokenUtils;

    private final WxMaService wxMaService;

    private final FileInfoService fileInfoService;

    private final DefaultAmountConfigMapper defaultAmountConfigMapper;

    private final ApplicationEventPublisher eventPublisher;

    private final UserPartnerPreferencesMapper userPartnerPreferencesMapper;

    private final UserInfoMapper userInfoMapper;

    @Override
    public Page<UserProfileInfoVo> getPage(Long pageNum, Long pageSize, UserProfileInfoVo userProfileInfoVo) {
        Page<UserProfileInfoVo> page = new Page<>(pageNum == null ? 1 : pageNum, pageSize == null ? 10 : pageSize);
        return userProfileInfoMapper.getPage(page, userProfileInfoVo, "list");
    }

    @Override
    public Page<UserProfileInfoVo> getPageWithMembership(Long pageNum, Long pageSize, UserProfileInfoVo userProfileInfoVo) {
        Page<UserProfileInfoVo> page = new Page<>(pageNum == null ? 1 : pageNum, pageSize == null ? 10 : pageSize);
        return userProfileInfoMapper.getPageWithMembership(page, userProfileInfoVo, "list");
    }

    @Override
    public UserProfileInfoVo queryUserProfileInfo(Long id) {
        return userProfileInfoMapper.queryUserProfileInfo(id);
    }

    @Override
    public UserProfileInfoVo queryUserProfileInfoByUserId(Long userId) {
        UserProfileInfoVo userProfileInfoVo = userProfileInfoMapper.queryUserProfileInfoByUserId(userId);
        if (userProfileInfoVo != null && userProfileInfoVo.getWechatQrCodeId() != null) {
            FileInfoVo fileInfoVo = null;
            try {
                fileInfoVo = fileInfoService.queryFileInfo(userProfileInfoVo.getWechatQrCodeId());
            } catch (Exception e) {
                log.error("查询用户微信二维码失败，userId:{}，错误信息：{}", userId, e.getMessage());
            }
            userProfileInfoVo.setWechatQrCodeFile(fileInfoVo);
        }
        return userProfileInfoVo;
    }

    @Override
    public void export(UserProfileInfoVo userProfileInfoVo, HttpServletResponse response) throws Exception {
        List<UserProfileVo> list = userProfileInfoMapper.getList(userProfileInfoVo, "list");
        List<UserProfileInfoExportVo> res = list.stream().map(up -> {
            UserProfileInfoExportVo vo = new UserProfileInfoExportVo();
            vo.setCode(up.getCode());
            vo.setPhone(up.getPhone());
            vo.setNickname(up.getNickname());
            String genderName = null;
            if (up.getGender() != null) {
                switch (up.getGender()) {
                    case "0":
                        genderName = "男";
                        break;
                    case "1":
                        genderName = "女";
                        break;
                    default:
                        genderName = "未知";
                }
            }
            vo.setGender(genderName);
            if (up.getBirthYearMonth() != null) {
                int age = java.time.Period.between(up.getBirthYearMonth(), java.time.LocalDate.now()).getYears();
                vo.setAge(age);
            }
            vo.setHeight(up.getHeight());
            vo.setWeight(up.getWeight());
            vo.setProfessionName(up.getProfessionName());
            vo.setIncomeStatusName(up.getIncomeStatusName());
            String region = "";
            if (up.getProvinceName() != null) {
                region += up.getProvinceName() + "/";
            }
            if (up.getCityName() != null) {
                region += up.getCityName() + "/";
            }
            if (up.getDistrictName() != null) {
                region += up.getDistrictName() + "/";
            }
            if (region.endsWith("/")) {
                region = region.substring(0, region.length() - 1);
            }
            vo.setRegion(region);
            if (up.getUserId() != null) {
                // 会员/红娘/合伙人信息
                // 查找会员信息
                List<MemberAboutVo> userMemberInfoList = userInfoMapper.getMemberAboutList(up.getUserId());
                if (userMemberInfoList != null && !userMemberInfoList.isEmpty()) {
                    MemberAboutVo about = userMemberInfoList.get(0);
                    vo.setMembershipFlag(Boolean.TRUE.equals(about.getMembershipFlag()) ? "是" : "否");
                    vo.setMembershipName(about.getMembershipName());
                    vo.setMatchmakerFlag(Boolean.TRUE.equals(about.getMatchmakerFlag()) ? "是" : "否");
                    vo.setPartnerFlag(Boolean.TRUE.equals(about.getPartnerFlag()) ? "是" : "否");
                    vo.setPartnerType(about.getPartnerCategoryName());
                }
                UserPartnerPreferencesVo pref = userPartnerPreferencesMapper.queryUserPartnerPreferencesByUserId(up.getUserId());
                if (pref != null) {
                    vo.setPrefAgeFrom(pref.getAgeFrom());
                    vo.setPrefAgeTo(pref.getAgeTo());
                    vo.setPrefHeightFrom(pref.getHeightFrom());
                    vo.setPrefHeightTo(pref.getHeightTo());
                    vo.setPrefWeightFrom(pref.getWeightFrom());
                    vo.setPrefWeightTo(pref.getWeightTo());
                    vo.setPrefEducationLevel(pref.getEducationLevelName());
                    vo.setPrefProfession(pref.getProfessionName());
                    vo.setPrefIncomeRange(pref.getIncomeRangeName());
                    vo.setPrefHousingCarStatus(pref.getHousingCarStatusName());
                    vo.setPrefMaritalStatus(pref.getMaritalStatusName());
                    String prefRegion = "";
                    if (pref.getProvinceName() != null) {
                        prefRegion += pref.getProvinceName() + "/";
                    }
                    if (pref.getCityName() != null) {
                        prefRegion += pref.getCityName() + "/";
                    }
                    if (pref.getDistrictName() != null) {
                        prefRegion += pref.getDistrictName() + "/";
                    }
                    if (prefRegion.endsWith("/")) {
                        prefRegion = prefRegion.substring(0, prefRegion.length() - 1);
                    }
                    vo.setPrefRegion(prefRegion);
                }
            }
            return vo;
        }).collect(java.util.stream.Collectors.toList());

        ExportParams exportParams = new ExportParams("用户档案", "用户档案");
        Workbook workbook = ExcelExportUtil.exportExcel(exportParams, UserProfileInfoExportVo.class, res);
        response.setContentType("application/vnd.ms-excel; charset=UTF-8");
        response.setHeader("Content-Disposition", "filename.xls");
        response.setHeader("Cache-Control", "no-cache");
        response.setHeader("Access-Control-Expose-Headers", "Content-Disposition");
        workbook.write(response.getOutputStream());
        response.flushBuffer();
        workbook.close();
    }

    @Override
    public UserProfileInfoVo addUserProfileInfo(UserProfileInfoVo userProfileInfoVo) throws Exception {
        // 校验用户是否存在档案
        LambdaQueryWrapper<UserProfileInfo> query = Wrappers.<UserProfileInfo>lambdaQuery()
                .eq(UserProfileInfo::getUserId, userProfileInfoVo.getUserId())
                .eq(UserProfileInfo::getDeleteFlag, 0);
        if (this.count(query) > 0) {
            throw new Exception("用户已存在档案，不能重复添加！");
        }
        UserProfileInfo userProfileInfo = new UserProfileInfo();
        BeanUtils.copyProperties(userProfileInfoVo, userProfileInfo);
        if (userProfileInfo.getBirthYearMonth() != null) {
            LocalDate birthYearMonth = userProfileInfo.getBirthYearMonth();
            userProfileInfo.setZodiac(getZodiac(birthYearMonth.getMonthValue(), birthYearMonth.getDayOfMonth()));
            userProfileInfo.setCnZodiac(getCnZodiac(birthYearMonth.getYear()));
        }
        userProfileInfoMapper.insert(userProfileInfo);
        // 查询用户编码，如果是2或者与当前性别不一致，则重新生成编码
        userInfoService.refreshUserCode(userProfileInfo.getUserId(), userProfileInfoVo.getGender());
        UserProfileInfoVo res = new UserProfileInfoVo();
        BeanUtils.copyProperties(userProfileInfo, res);
        return res;
    }

    @Override
    public UserProfileInfoVo updateUserProfileInfo(UserProfileInfoVo userProfileInfoVo) throws Exception {
//        // 查找是否有红娘信息
//        MatchmakerInfoVo dbMatchmaker = matchmakerInfoMapper.queryMatchmakerInfoByUserId(userProfileInfoVo.getUserId());
//        if (dbMatchmaker != null) {
//            throw new RuntimeException("您是红娘，不能修改用户信息！");
//        }
        UserProfileInfoVo dbUserInfo = queryUserProfileInfoByUserId(userProfileInfoVo.getUserId());
        log.info("===============================================数据库profileInfo:{}", JSONObject.toJSONString(dbUserInfo));
        UserProfileInfo userProfileInfo = new UserProfileInfo();
        BeanUtils.copyProperties(userProfileInfoVo, userProfileInfo);
        if (userProfileInfo.getBirthYearMonth() != null) {
            LocalDate birthYearMonth = userProfileInfo.getBirthYearMonth();
            userProfileInfo.setZodiac(getZodiac(birthYearMonth.getMonthValue(), birthYearMonth.getDayOfMonth()));
            userProfileInfo.setCnZodiac(getCnZodiac(birthYearMonth.getYear()));
        }
        if (dbUserInfo != null) {
            userProfileInfo.setId(dbUserInfo.getId());
        }
        if (StringUtils.isBlank(userProfileInfo.getContactPhone())) {
            userProfileInfo.setContactPhone(null);
        }
        log.info("===============================================数据库update profileInfo:{}", JSONObject.toJSONString(userProfileInfo));
        // 
        UserInfoVo curUser = userInfoService.queryUserInfo(userProfileInfo.getUserId());
        if (curUser.getIntroUserId() != null && dbUserInfo != null
                && dbUserInfo.getFirstFlag() && "gzh".equals(curUser.getFromSource())) {
            DefaultAmountConfigVo defaultAmountConfigVo = defaultAmountConfigMapper.queryDefaultAmountConfigByCode("join-love");
            log.info("邀请人id: {}, 红包金额: {}", curUser.getIntroUserId(), defaultAmountConfigVo.getAmount());
            RedPacketVo redPacketVo = new RedPacketVo();
            redPacketVo.setAmount(defaultAmountConfigVo.getAmount());
            redPacketVo.setActName("邀请红包");
            redPacketVo.setWishing("恭喜发财，大吉大利");
            redPacketVo.setRemark("新人完善信息！");
            redPacketVo.setInvitedUserId(curUser.getId());
            redPacketVo.setUserId(curUser.getIntroUserId());
            eventPublisher.publishEvent(new UserInviteRedPacketEvent(this, redPacketVo));
            userProfileInfo.setFirstFlag(false);
        }

        userProfileInfoMapper.updateById(userProfileInfo);
        // 保存userActivityInfo
        UserActivityInfoVo userActivityInfoVo = new UserActivityInfoVo();
        userActivityInfoVo.setUserId(userProfileInfo.getUserId());
        if (StringUtils.isNotBlank(userProfileInfo.getGender())) {
            userActivityInfoVo.setGender(userProfileInfo.getGender());
        }
        if (StringUtils.isNotBlank(userProfileInfo.getProfession())) {
            userActivityInfoVo.setProfession(userProfileInfo.getProfession());
        }
        if (StringUtils.isNotBlank(userProfileInfo.getIncomeStatus())) {
            userActivityInfoVo.setIncomeStatus(userProfileInfo.getIncomeStatus());
        }
        if (userProfileInfo.getProvinceId() != null) {
            userActivityInfoVo.setProvinceId(userProfileInfo.getProvinceId());
        }
        if (userProfileInfo.getCityId() != null) {
            userActivityInfoVo.setCityId(userProfileInfo.getCityId());
        }
        if (userProfileInfo.getDistrictId() != null) {
            userActivityInfoVo.setDistrictId(userProfileInfo.getDistrictId());
        }
        if (userProfileInfo.getHeight() != null) {
            userActivityInfoVo.setHeight(userProfileInfo.getHeight());
        }
        if (userProfileInfo.getWeight() != null) {
            userActivityInfoVo.setWeight(userProfileInfo.getWeight());
        }
        if (userProfileInfo.getBirthYearMonth() != null) {
            userActivityInfoVo.setBirthYearMonth(userProfileInfo.getBirthYearMonth());
        }
        userActivityInfoService.addInfo(userActivityInfoVo);
        if (userProfileInfoVo.getGender() != null) {
            userInfoService.refreshUserCode(userProfileInfo.getUserId(), userProfileInfoVo.getGender());
        }

        if (StringUtils.isNotBlank(userProfileInfo.getContactPhone())) {
            if (StringUtils.isBlank(curUser.getPhone()) || !curUser.getPhone().equals(userProfileInfo.getContactPhone())) {
                curUser.setPhone(userProfileInfo.getContactPhone());
                userInfoService.updateUserInfo(curUser);
            }
        }
        return userProfileInfoVo;
    }

    @Override
    public Boolean deleteUserProfileInfo(String ids) {
        if (StringUtils.isEmpty(ids)) {
            return true;
        }
        List<String> idArr = Arrays.asList(ids.split(","));
        userProfileInfoMapper.deleteBatchIds(idArr);
        return true;
    }

    public String getCnZodiac(int year) {
        // 生肖对应的英文名称
        String[] zodiac = {"monkey", "rooster", "dog", "pig", "rat", "ox", "tiger", "rabbit", "dragon", "snake", "horse", "goat"};
        return zodiac[year % 12]; // 返回对应的生肖英文名称
    }

    public String getZodiac(int month, int day) {
        if ((month == 3 && day >= 21) || (month == 4 && day <= 19)) {
            return "aries"; // 白羊座
        } else if ((month == 4 && day >= 20) || (month == 5 && day <= 20)) {
            return "taurus"; // 金牛座
        } else if ((month == 5 && day >= 21) || (month == 6 && day <= 21)) {
            return "gemini"; // 双子座
        } else if ((month == 6 && day >= 22) || (month == 7 && day <= 22)) {
            return "cancer"; // 巨蟹座
        } else if ((month == 7 && day >= 23) || (month == 8 && day <= 22)) {
            return "leo"; // 狮子座
        } else if ((month == 8 && day >= 23) || (month == 9 && day <= 22)) {
            return "virgo"; // 处女座
        } else if ((month == 9 && day >= 23) || (month == 10 && day <= 23)) {
            return "libra"; // 天秤座
        } else if ((month == 10 && day >= 24) || (month == 11 && day <= 22)) {
            return "scorpio"; // 天蝎座
        } else if ((month == 11 && day >= 23) || (month == 12 && day <= 21)) {
            return "sagittarius"; // 射手座
        } else if ((month == 12 && day >= 22) || (month == 1 && day <= 19)) {
            return "capricorn"; // 摩羯座
        } else if ((month == 1 && day >= 20) || (month == 2 && day <= 18)) {
            return "aquarius"; // 水瓶座
        } else if ((month == 2 && day >= 19) || (month == 3 && day <= 20)) {
            return "pisces"; // 双鱼座
        }
        return "unknown constellation"; // 未知星座
    }

    @Override
    public String concatPhone(HttpServletRequest request, Long userId, String phone, String code, String changePhone) throws Exception {
        if (StringUtils.isBlank(phone)) {
            throw new Exception("电话号码不能为空！");
        }
        if (StringUtils.isNotBlank(code)) {
            String aliCode = redisUtils.get(LoginKey.loginPhoneCode.getPrefix() + RedisConstants.SEGMENTATION + phone);
            if (!code.equals(aliCode)) {
                //密码错误，返回提示信息
                throw new LoginException(ResultEnum.USER_PHONE_OR_CODE_ERROR);
            }
        }

        if ("changePhone".equals(changePhone)) {
            UserProfileInfoVo userProfileInfoVo = queryUserProfileInfoByUserId(userId);
            if (userProfileInfoVo == null) {
                userProfileInfoVo = new UserProfileInfoVo();
                userProfileInfoVo.setUserId(userId);
                userProfileInfoVo.setContactPhone(phone);
                addUserProfileInfo(userProfileInfoVo);
            } else {
                userProfileInfoVo.setContactPhone(phone);
                updateUserProfileInfo(userProfileInfoVo);
            }
            return userId.toString();
        }

        // 查询手机号是否存在
        UserInfoVo phoneUser = userInfoService.queryUserInfoByPhone(phone);

        // 如果用户id是当前id则是同一个用户
        if (phoneUser == null || Objects.equals(phoneUser.getId(), userId)) {
            phoneUser = null;
        }

        UserInfoVo userInfoVo = userInfoService.queryUserInfo(userId);

        if (phoneUser == null) {
            if (userInfoVo == null) {
                throw new SystemException(ResultEnum.USER_NOT_EXIST);
            }
            if (!phone.equals(userInfoVo.getPhone())) {
                userInfoVo.setPhone(phone);
                userInfoService.updateUserInfo(userInfoVo);
            }
            UserProfileInfoVo userProfileInfoVo = queryUserProfileInfoByUserId(userId);
            if (userProfileInfoVo == null) {
                userProfileInfoVo = new UserProfileInfoVo();
                userProfileInfoVo.setUserId(userId);
                userProfileInfoVo.setContactPhone(phone);
                addUserProfileInfo(userProfileInfoVo);
            } else {
                userProfileInfoVo.setContactPhone(phone);
                updateUserProfileInfo(userProfileInfoVo);
            }
        } else {
            // 如何是修改手机号接口，且手机号存在
            if ("changePhone".equals(changePhone)) {
                throw new SystemException("1200002", "手机号已被注册！");
            }
            // 如果存在且关联手机号，则报错
            if (StringUtils.isNotBlank(phoneUser.getWechatOpenid())) {
                throw new SystemException("1200001", "手机号已关联其他微信号！");
            }
            // 如果存在且当前没有关联手机号 并且当前用户也没有关联手机号，
            phoneUser.setWechatOpenid(userInfoVo.getWechatOpenid());
            phoneUser.setWechatUnionid(userInfoVo.getWechatUnionid());
            phoneUser.setWechatGzhOpenid(userInfoVo.getWechatGzhOpenid());
            phoneUser.setWechatBindTime(userInfoVo.getWechatBindTime());
            if (phoneUser.getIntroUserId() == null) {
                phoneUser.setIntroUserId(userInfoVo.getIntroUserId());
            }
            userInfoService.updateUserInfo(phoneUser);
            log.info("更新手机号用户信息： {}", JSONObject.toJSONString(phoneUser));
            // 修改当前登录的登录信息
            long expiration = audience.getExpiresSecond();
            String tokenUuid = request.getHeader(audience.getTokenHeader());
            String jwtToken = audience.getTokenHead() + jwtTokenUtils.createJwt(String.valueOf(phoneUser.getId()), phoneUser.getId(), phoneUser.getUsername(), audience.getClientId(), audience.getName()
                    , -1, audience.getBase64Secret());
            redisUtils.setEx(LoginKey.loginUuid, tokenUuid, jwtToken, expiration, TimeUnit.SECONDS);
            redisUtils.setEx(LoginKey.loginAdmin, jwtToken, JSONObject.toJSONString(phoneUser), expiration, TimeUnit.SECONDS);
            String ip = IpUtils.getIpAddr(request);
            redisUtils.setEx(LoginKey.loginAdmin, ip + RedisConstants.SEGMENTATION + phoneUser.getId(), JSONObject.toJSONString(phoneUser), expiration, TimeUnit.SECONDS);
            log.info("生成token信息： {}", jwtToken);
            // 删除当前人，然后返回用户id
            userInfoService.deleteUserInfo(String.valueOf(userInfoVo.getId()));
        }
        return phoneUser != null ? phoneUser.getId().toString() : userInfoVo.getId().toString();
    }

    @Override
    public String concatPhoneByCode(HttpServletRequest request, Long userId, String code) throws Exception {
        WxMaPhoneNumberInfo phoneInfo = getPhoneByWechatCode(request, code);
        if (phoneInfo != null && StringUtils.isNotBlank(phoneInfo.getPhoneNumber())) {
            // 成功获取手机号
            return concatPhone(request, userId, phoneInfo.getPhoneNumber(), null, "changeWechat");
        } else {
            // 返回错误信息
            throw new Exception("Error: ");
        }
    }

    @Override
    public WxMaPhoneNumberInfo getPhoneByWechatCode(HttpServletRequest request, String code) throws Exception {
        if (StringUtils.isBlank(code)) {
            throw new Exception("编码不能为空！");
        }
        log.info("获取到的手机号码开始： {}", code);
        WxMaPhoneNumberInfo phoneNoInfo = wxMaService.getUserService().getPhoneNoInfo(code);
        log.info("获取到的手机号码结束： {}", JSONObject.toJSONString(phoneNoInfo));
        if (phoneNoInfo != null && StringUtils.isNotBlank(phoneNoInfo.getPhoneNumber())) {
            // 成功获取手机号
            return phoneNoInfo;
        } else {
            // 返回错误信息
            throw new Exception("Error: ");
        }
    }
}
